//
// Created by lxx on 2021/9/2.
//

#include "GenMicro.cuh"
#include <algorithm/rayTracing/qmcrt_util/global_function.cuh>

using namespace solar::cuda;

__global__ static void map_micro(float3* helio_origin, float3* helio_normal, float3* micro_orign,
                                 float3* micro_normal, float3 helio_size, int2 rowcol,
                                 int2 sub_rowcol, float pixel_length, float2 gap, int map_size,
                                 size_t micro_nums)
{
    auto my_id = global_func::getThreadID();
    if (my_id >= micro_nums)
    {
        return;
    }
    int current_helio = my_id / map_size;       // myid 所属的heliostat 编号
    int curr_micro_in_helio = my_id % map_size; // myid在heliostat中所属的microheliosta 编号
    // printf("%d\n",current_helio);
    float3 current_origin = helio_origin[current_helio];
    float3 current_normal = helio_normal[current_helio];
    micro_orign[my_id] = current_origin;
    micro_normal[my_id] = current_normal;

    int row = curr_micro_in_helio / (rowcol.y * sub_rowcol.y);
    int col = curr_micro_in_helio % (rowcol.y * sub_rowcol.y);

    int block_row = row / sub_rowcol.x;
    int block_col = col / sub_rowcol.y;

    // 1. Generate local micro-heliostats' centers
    micro_orign[my_id].x =
        col * pixel_length + block_col * gap.x + pixel_length / 2 - helio_size.x / 2;
    micro_orign[my_id].y = helio_size.y / 2;
    micro_orign[my_id].z =
        row * pixel_length + block_row * gap.y + pixel_length / 2 - helio_size.z / 2;

    // 2. Generate micro-heliostats' normals
    micro_normal[my_id] = current_normal;

    // 3. Transform local micro-heliostat center to world position.
    float3 local = micro_orign[my_id];
    local = global_func::local2world_rotate(local, current_normal);
    local = global_func::translate(local, current_origin);
    micro_orign[my_id] = local;
}

void solar::cuda::genmicro(float3* helio_origin, float3* helio_normal, float3*& micro_orign,
                           float3*& micro_normal, float3 helio_size, int2 rowcol, int2 sub_rowcol,
                           float pixel_length, float2 gap, int map_size, size_t micro_nums)
{

    int n_threads = 512;
    dim3 n_blocks;
    global_func::setThreadBlocks(n_blocks, n_threads, micro_nums);
    map_micro<<<n_blocks, n_threads>>>(helio_origin, helio_normal, micro_orign, micro_normal,
                                       helio_size, rowcol, sub_rowcol, pixel_length, gap, map_size,
                                       micro_nums);

    cudaDeviceSynchronize();
    checkCudaErrors(cudaGetLastError());
}
